﻿using System;
using System.Threading.Tasks;

using ApproveFlowEngine.Core.Base;
using ApproveFlowEngine.Core.Nodes;
using ApproveFlowEngine.Enums.Core;

using Volo.Abp.Domain.Repositories;
using Volo.Abp.Domain.Services;
using Volo.Abp.Guids;

namespace ApproveFlowEngine.Core
{
    public class WorkFlowDomainService : DomainService
    {
        #region Private Fields

        private readonly IRepository<WorkFlow> _flowRepository;
        private readonly IGuidGenerator _guidGenerator;

        #endregion Private Fields

        #region Public Constructors

        public WorkFlowDomainService(IRepository<WorkFlow> flowRepository, IGuidGenerator guidGenerator)
        {
            _flowRepository = flowRepository;
            _guidGenerator = guidGenerator;
        }

        #endregion Public Constructors



        #region Public Methods

        public async Task<WorkFlow> Create(long flowNo, string flowName, string remark = "", ApproveType approveType = ApproveType.General, ApproveFlowStatus flowStatus = ApproveFlowStatus.None)
        {
            var isAny = await _flowRepository.AnyAsync(c => c.FlowNo == flowNo);
            if (isAny)
            {
                throw new Exception("审批单号已存在！");
            }
            var flowId = _guidGenerator.Create();
            var result = new WorkFlow(flowId, flowNo, flowName, remark, approveType, flowStatus);
            var root = CreateSerialNode(result);
            result.SetRoot(root);
            return result;
        }

        public WorkNodeComplex CreateComplexNode(WorkFlow flow, NodeType nodeType)
        {
            var node= nodeType switch
            {
                NodeType.Countersign or
                NodeType.Serial or
                NodeType.Parallel => CreateNode(flow,nodeType),
                NodeType.Simple => throw new Exception("节点类型错误！"),
                _ => throw new Exception("节点类型错误！"),
            };
            return (WorkNodeComplex)node;
        }

        public WorkNodeCountersign CreateCountersignNode(WorkFlow flow)
        {
            return (WorkNodeCountersign)CreateComplexNode(flow, NodeType.Countersign);
        }

        public WorkNode CreateNode(WorkFlow flow, NodeType nodeType)
        {
            WorkNode node;
            switch (nodeType)
            {
                case NodeType.Simple:

                    node=  new WorkNode( _guidGenerator.Create());
                    node.SetFlow(flow);
                    break;

                case NodeType.Countersign:
                    node = new WorkNodeCountersign( _guidGenerator.Create());
                    node.SetFlow(flow);
                    break;
                case NodeType.Serial:
                    node= new WorkNodeSerial( _guidGenerator.Create());
                    node.SetFlow(flow);
                    break;
                case NodeType.Parallel:
                    node= new WorkNodeParallel( _guidGenerator.Create());
                    node.SetFlow(flow);
                    break;
                default:
                    throw new Exception($"Cannot create node: {nodeType}");
            }
            return node;
        }

        public WorkNodeSerial CreateSerialNode(WorkFlow flow)
        {
            return (WorkNodeSerial)CreateComplexNode(flow, NodeType.Serial);
        }

        public WorkNode CreateSimple(WorkFlow flow)
        {
            var node= new WorkNode( _guidGenerator.Create());
            node.SetFlow(flow);
            return node;
        }

        #endregion Public Methods
    }
}